#include <graphics/VertexData.h>

namespace ne
{
    VertexData::VertexData(const PrimitiveType pt)
        : mPrimitiveType(pt),
          mStride(0),
          mSize(0),
          mNeedSizeUpdate(false)
    {
    }

    PrimitiveType VertexData::getPrimitiveType() const
    {
        return mPrimitiveType;
    }

    void VertexData::setStride(const uint32_t stride)
    {
        mStride = stride;
    }

    uint32_t VertexData::getStride() const
    {
        return mStride;
    }

    VertexAttributePtr VertexData::createAttribute(const uint32_t bufferSource,
                                                   const AttributeSemantic semantic,
                                                   const AttributeType type,
                                                   const uint32_t count,
                                                   const uint32_t stride,
                                                   const size_t offset,
                                                   const bool normalized)
    {
        if (semantic != VAS_INDEX)
        {
            VertexAttributeMapConstIterator it = mAttributeMap.find(semantic);
            if (it == mAttributeMap.end())
            {
                VertexAttributePtr pAttribute(
                    new VertexAttribute(bufferSource, semantic, type,
                                        count, stride, offset, normalized));
                mAttributeMap[semantic] = pAttribute;
                needUpdateSize();
                return pAttribute;
            }
        }
        return VertexAttributePtr();
    }

    bool VertexData::hasAttribute(const AttributeSemantic semantic) const
    {
        VertexAttributeMapConstIterator it = mAttributeMap.find(semantic);
        if (it != mAttributeMap.end())
        {
            return true;
        }
        return false;
    }

    VertexAttributePtr VertexData::getAttribute(const AttributeSemantic semantic) const
    {
        VertexAttributeMapConstIterator it = mAttributeMap.find(semantic);
        if (it != mAttributeMap.end())
        {
            return it->second;
        }
        return VertexAttributePtr();
    }

    uint32_t VertexData::getSize() const
    {
        _updateSize();
        return mSize;
    }

    uint32_t VertexData::getAttributeCount() const
    {
        return uint32_t(mAttributeMap.size());
    }

    const VertexAttributeMap& VertexData::getAttributeMap() const
    {
        return mAttributeMap;
    }

    bool VertexData::removeAttribute(VertexAttributePtr &pAttribute)
    {
        if (pAttribute.notNull())
        {
            return removeAttribute(pAttribute->getSemantic());
        }
        return false;
    }

    bool VertexData::removeAttribute(const AttributeSemantic semantic)
    {
        VertexAttributeMapIterator it = mAttributeMap.find(semantic);
        if (it != mAttributeMap.end())
        {
            mAttributeMap.erase(it);
            needUpdateSize();
            return true;
        }
        return false;
    }

    void VertexData::removeAll()
    {
        mAttributeMap.clear();
        needUpdateSize();
    }

    void VertexData::needUpdateSize()
    {
        mNeedSizeUpdate = true;
    }

    VertexData::~VertexData()
    {
        removeAll();
    }

    void VertexData::_updateSize() const
    {
        if (mNeedSizeUpdate)
        {
            mSize = 0;
            for (VertexAttributeMapConstIterator it=mAttributeMap.begin(); it!=mAttributeMap.end(); ++it)
            {
                mSize += it->second->getSize();
            }
            mNeedSizeUpdate = false;
        }
    }
}
